home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / Other Langs / MacPerl ƒ / Perl Source ƒ / MacPerl / MPUtils.c < prev    next >
Text File  |  1993-12-12  |  24KB  |  983 lines

  1. /*********************************************************************
  2. Project    :    MacPerl            -    Real Perl Application
  3. File        :    MPEditUtils.c    -
  4. Author    :    Matthias Neeracher
  5.  
  6. A lot of this code is borrowed from 7Edit written by
  7. Apple Developer Support UK
  8.  
  9. Started    :    17Mar93                                Language    :    MPW C
  10. Modified    :    29May93    MN    Compiles correctly
  11.                 30May93    MN    Support Console Windows
  12.                 14Aug93    MN    Preference file
  13.                 15Aug93    MN    DoAbout
  14.                 17Aug93    MN    DoPrefDialog()
  15. Last        :    17Aug93
  16. *********************************************************************/
  17.  
  18. #include <PLStringFuncs.h>
  19. #include <Events.h>
  20. #include <Traps.h>
  21. #include <Dialogs.h>
  22. #include <Fonts.h>
  23. #include <Packages.h>
  24. #include <ToolUtils.h>
  25. #include <AppleEvents.h>
  26. #include <TFileSpec.h>
  27. #include <Folders.h>
  28. #include <Resources.h>
  29. #include <OSUtils.h>
  30. #include <Files.h>
  31. #include <Lists.h>
  32. #include <Icons.h>
  33. #include <string.h>
  34. #include <GUSI.h>
  35. #include <Desk.h>
  36. #include <ctype.h>
  37. #include <stdio.h>
  38.  
  39. #include "MPUtils.h"
  40. #include "MPWindow.h"
  41. #include <patchlevel.h>
  42.  
  43. /**-----------------------------------------------------------------------
  44.         Name:         ShowError
  45.         Purpose:        Reports an error to the user as both string and number.
  46.     -----------------------------------------------------------------------**/
  47. #pragma segment Utils
  48.  
  49. pascal void ShowError(Str255 theError, long theErrorCode)
  50. {
  51.     short     alertResult;
  52.     Str255    theString;
  53.  
  54.     if (gAppleEventsImplemented)
  55.         if (AEInteractWithUser(kAEDefaultTimeout, nil,nil))
  56.             return;
  57.         
  58.      SetCursor(&qd.arrow);
  59.      NumToString(theErrorCode, theString);
  60.      ParamText(theError, theString, "", "");
  61.      alertResult = Alert(300, nil);
  62. } /* ShowError */
  63.  
  64. /**-----------------------------------------------------------------------
  65.         Name:         Ours
  66.         Purpose:        Checks the frontmost window belongs to the app.
  67.     -----------------------------------------------------------------------**/
  68. #pragma segment Utils
  69.  
  70. pascal Boolean Ours(WindowPtr aWindow)
  71. {
  72.     if (aWindow)
  73.         if (((WindowPeek)aWindow)->windowKind == zoomDocProc)
  74.             return(true);
  75.  
  76.     return(false);
  77. } /* Ours */
  78.  
  79. /**-----------------------------------------------------------------------
  80.         Name:         SetShortMenus
  81.         Purpose:        Cuts the menus down to a minimum - Apple File Edit.
  82.                         Greys out the unavailable options - used when no docs open
  83.     -----------------------------------------------------------------------**/
  84. #pragma segment Utils
  85.  
  86. pascal void SetShortMenus()
  87. {
  88.     DeleteMenu(windowID);
  89.     
  90.     DisableItem(myMenus[fileM], fmClose);
  91.     DisableItem(myMenus[fileM], fmSave);
  92.     DisableItem(myMenus[fileM], fmSaveAs);
  93.     DisableItem(myMenus[fileM], fmRevert);
  94.     DisableItem(myMenus[fileM], fmPrint);
  95.     DisableItem(myMenus[fileM], fmPageSetUp);
  96.  
  97.     /* now the unnecessary items on the edit menu */
  98.  
  99.     DisableItem(myMenus[editM], undoCommand);
  100.     DisableItem(myMenus[editM], cutCommand);
  101.     DisableItem(myMenus[editM], copyCommand);
  102.     DisableItem(myMenus[editM], clearCommand);
  103.     DisableItem(myMenus[editM], pasteCommand);
  104.     DisableItem(myMenus[editM], selectAllCommand);
  105.  
  106.     DrawMenuBar();
  107. }  /* SetShortMenus */
  108.  
  109. /**-----------------------------------------------------------------------
  110.         Name:         SetLongMenus
  111.         Purpose:        Reinstates the full menu bar - called when first document
  112.                     opened.
  113.     -----------------------------------------------------------------------**/
  114. #pragma segment Utils
  115.  
  116. pascal void SetLongMenus()
  117. {
  118.     InsertMenu(myMenus[windowM], perlID);
  119.     
  120.     EnableItem(myMenus[fileM], fmClose);
  121.     EnableItem(myMenus[fileM], fmSave);
  122.     EnableItem(myMenus[fileM], fmSaveAs);
  123.     EnableItem(myMenus[fileM], fmRevert);
  124.     EnableItem(myMenus[fileM], fmPrint);
  125.     EnableItem(myMenus[fileM], fmPageSetUp);
  126.  
  127.     /* now the necessary items on the edit menu -
  128.         many other items fixed on each pass thru the main event
  129.         loop or before the window pulled down
  130.     */
  131.  
  132.     EnableItem(myMenus[editM], selectAllCommand);
  133.  
  134.     DrawMenuBar();
  135. }  /* SetLongMenus */
  136.  
  137. /**-----------------------------------------------------------------------
  138.     Name:       SetEditMenu
  139.     Purpose:    Set the text of the edit menu according to the state of
  140.                      current document.
  141.   -----------------------------------------------------------------------**/
  142.  
  143. #pragma segment Utils
  144.  
  145. pascal void SetEditMenu(DPtr theDoc)
  146. {
  147. #ifndef RUNTIME
  148.     if (theDoc->kind == kDocumentWindow && theDoc->u.reg.showBorders)
  149.         SetItem(myMenus[editM], cBorders, "\pHide Borders");
  150.     else
  151.         SetItem(myMenus[editM], cBorders, "\pShow Borders");
  152. #endif
  153. }  /* SetEditMenu */
  154.  
  155. /**-----------------------------------------------------------------------
  156.     Name:       GetTempFileName
  157.     Purpose:    Fills newstring with a temporary file name.
  158.   -----------------------------------------------------------------------**/
  159.  
  160. #pragma segment Utils
  161.  
  162. pascal void GetTempFileName(DPtr aDoc, Str255 newString)
  163. {
  164.     Str255        s;
  165.     Str255        fileName;
  166.  
  167.     if (aDoc->kind != kDocumentWindow || aDoc->u.reg.everSaved == false)
  168.         PLstrcpy(fileName, "\pMacPerlTmp");
  169.     else
  170.         PLstrcpy(fileName, aDoc->theFileName);
  171.  
  172.     /*generate a unique(ish) temporary filename*/
  173.  
  174.     if (fileName[0] > 21)
  175.         fileName[0] = 21;
  176.  
  177.     NumToString(TickCount(), s);
  178.  
  179.     PLstrcat(fileName, s);
  180.  
  181.     PLstrcpy(newString,fileName);
  182. }
  183.  
  184. /**-----------------------------------------------------------------------
  185.     Name:       SetText
  186.     Purpose:    Sets the text of the supplied itemNo in aDialog to
  187.                     theString and select it.
  188.   -----------------------------------------------------------------------**/
  189.  
  190. #pragma segment Utils
  191.  
  192. pascal void SetText(DialogPtr aDialog, short itemNo, Str255 theString)
  193. {
  194.     Handle      itemHandle;
  195.     Rect        box;
  196.     short       kind;
  197.     TEHandle    theTEHandle;
  198.  
  199.     GetDItem(aDialog, itemNo, &kind, &itemHandle, &box);
  200.     SetIText(itemHandle, theString);
  201.  
  202.     theTEHandle = ((DialogPeek)aDialog)->textH;
  203.  
  204.     /*set all the text to be selected*/
  205.     if (theTEHandle)
  206.         TESetSelect(0, 255, theTEHandle);
  207. }
  208.  
  209. /**-----------------------------------------------------------------------
  210.     Name:       RetrieveText
  211.     Purpose:    Returns the text of anItem in aDialog in aString.
  212.   -----------------------------------------------------------------------**/
  213.  
  214. #pragma segment Utils
  215.  
  216. pascal void RetrieveText(DialogPtr aDialog, short anItem, Str255 aString)
  217. {
  218.     short      kind;
  219.     Rect       box;
  220.     Handle     itemHandle;
  221.  
  222.     GetDItem(aDialog, anItem, &kind, &itemHandle, &box);
  223.     GetIText(itemHandle, aString);
  224. }
  225.  
  226. /**-----------------------------------------------------------------------
  227.     Name:      DrawDefaultOutline
  228.     Purpose:   Draws an outline around theItem.
  229.                     Called as a useritem Proc by the dialog manager.
  230.                     To use place a useritem over the default item in the
  231.                     dialog and install the address of this proc as the item
  232.                     handle.
  233.   -----------------------------------------------------------------------**/
  234.  
  235. #pragma segment Utils
  236.  
  237. pascal void DrawDefaultOutline(DialogPtr theDialog, short theItem)
  238. {
  239.     short       kind;
  240.     Handle      itemHandle;
  241.     Rect        box;
  242.  
  243.     GetDItem(theDialog, theItem, &kind, &itemHandle, &box);
  244.     PenSize(3, 3);
  245.     InsetRect(&box, -4, -4);
  246.     FrameRoundRect(&box, 16, 16);
  247.     PenNormal();
  248. }  /* DrawDefaultOutline */
  249.  
  250. /**-----------------------------------------------------------------------
  251.     Name:       AdornDefaultButton
  252.     Purpose:    Installs DrawDefaultOutline as the useritem proc
  253.                      for the given item.
  254. -----------------------------------------------------------------------**/
  255.  
  256. #pragma segment Utils
  257.  
  258. pascal void AdornDefaultButton(DialogPtr theDialog,short theItem)
  259. {
  260.     short        kind;
  261.     Handle    itemHandle;
  262.      Rect        box;
  263.  
  264.     GetDItem(theDialog, theItem, &kind, &itemHandle, &box);
  265.     SetDItem(theDialog, theItem, kind, (Handle)&DrawDefaultOutline, &box);
  266. }
  267.  
  268. pascal void GetRectOfDialogItem(DialogPtr theDialog, short theItem, Rect *theRect)
  269. {
  270.     short       kind;
  271.     Handle      itemHandle;
  272.  
  273.     GetDItem(theDialog, theItem, &kind, &itemHandle, theRect);
  274. }
  275.  
  276. /**------  FeatureIsImplemented    ------------**/
  277. /*    This is called to use Gestalt to determine if a feature is implemented.
  278.      This applies to only those referenced by OSType    */
  279.  
  280. #pragma segment Utils
  281.  
  282. pascal Boolean FeatureIsImplemented(OSType theFeature, short theTestBit)
  283. {
  284.      long      result;
  285.  
  286.     return !Gestalt(theFeature, &result) && (result & (1 << theTestBit));
  287. }
  288.  
  289. #pragma segment Utils
  290.  
  291. pascal Boolean CheckEnvironment()
  292. {
  293.     /*check for the AppleEvents manager - we certainly can't work without it*/
  294.  
  295.     gAppleEventsImplemented   = FeatureIsImplemented(gestaltAppleEventsAttr, gestaltAppleEventsPresent);
  296.  
  297. #ifndef RUNTIME
  298.     /*first check if the Edition Manager is present*/
  299.  
  300.     gEditionManagerImplemented = FeatureIsImplemented(gestaltEditionMgrAttr, gestaltEditionMgrPresent);
  301.  
  302.     /*and for good measure- the Alias manager*/
  303.  
  304.     gAliasManagerImplemented  = FeatureIsImplemented(gestaltAliasMgrAttr, gestaltAliasMgrPresent);
  305.  
  306.     /*check if recording is implemented*/
  307.  
  308.     gRecordingImplemented   = FeatureIsImplemented(gestaltAppleEventsAttr,1);
  309.  
  310.     /*check for the Outline fonts*/
  311.  
  312.     gOutlineFontsImplemented  = FeatureIsImplemented(gestaltFontMgrAttr, gestaltOutlineFonts);
  313.  
  314.     return     gEditionManagerImplemented &&
  315.                 gAliasManagerImplemented   &&
  316.                 gAppleEventsImplemented    &&
  317.                 gOutlineFontsImplemented;
  318. #else
  319.     return true;
  320. #endif
  321. }  /* CheckEnvironment */
  322.  
  323. /*
  324.     DoPageSetup returns true if the page setup of the document is altered
  325. */
  326.  
  327. pascal Boolean DoPageSetup(DPtr theDoc)
  328. {
  329.     if (theDoc) {
  330.         Boolean result;
  331.  
  332.         PrOpen();
  333.         result =  PrStlDialog(theDoc->thePrintSetup);
  334.         PrClose();
  335.  
  336.         return(result);
  337.     }
  338. }  /* DoPageSetup */
  339.  
  340. /*
  341.     Name:    CtrlKeyPressed
  342.     Purpose: Returns true if control key pressed during event
  343. */
  344. pascal Boolean CtrlKeyPressed(const EventRecord *theEvent)
  345. {
  346.     return theEvent->modifiers & controlKey;
  347. }
  348.  
  349. /*
  350.     Name:    OptionKeyPressed
  351.     Purpose: Returns true if option key pressed during event
  352. */
  353. pascal Boolean OptionKeyPressed(const EventRecord *theEvent)
  354. {
  355.     return theEvent->modifiers & optionKey;
  356. }
  357.  
  358. pascal void DrawVersion(DialogPtr dlg, short item)
  359. {
  360.     VersRecHndl    vers;
  361.     short            base;
  362.     Handle        h;
  363.     Rect            r;
  364.     FontInfo        info;
  365.     Str15            patchlevel;
  366.  
  367.     GetDItem(dlg, item, &base, &h, &r);
  368.     SetPort(dlg);
  369.     TextFont(1);
  370.     TextSize(10);
  371.     GetFontInfo(&info);
  372.     
  373.     base = r.top+2+info.ascent;
  374.     MoveTo(r.left+2, base);
  375.     DrawString("\pVersion");
  376.     MoveTo((r.left+r.right) >> 1, r.top+2+info.ascent);
  377.     
  378.     vers = (VersRecHndl) GetResource('vers', 1);
  379.     HLock((Handle) vers);
  380.     DrawString((*vers)->shortVersion);
  381.     ReleaseResource((Handle) vers);
  382.  
  383.     base += info.ascent + info.descent + info.leading;
  384.     MoveTo(r.left+2, base);
  385.     DrawString("\pPatchlevel");
  386.     MoveTo((r.left+r.right) >> 1, base);
  387.     patchlevel[0] = sprintf((char *) patchlevel+1, "%d", PATCHLEVEL);
  388.     DrawString(patchlevel);
  389.  
  390.     TextFont(CreditID);
  391.     TextSize(12);
  392. }
  393.  
  394. pascal void DoAbout()
  395. {
  396.     DialogPtr    dlg;
  397.     short            kind;
  398.     Handle        hdl;
  399.     Rect            bounds;
  400.     Rect             hot;
  401.     Str255        string;
  402.     short *        widths;
  403.     short            count;
  404.     short            current;
  405.     short            offset;
  406.     EventRecord    ev;
  407.     RgnHandle    rgn;
  408.     long            lastTicks;
  409.     
  410.     SetCursor(&qd.arrow);
  411.     
  412.     dlg = GetNewDialog(AboutDialog, nil, (WindowPtr) -1);
  413.  
  414.     GetDItem(dlg, 2, &kind, &hdl, &bounds);
  415.     SetDItem(dlg, 2, kind, (Handle) DrawVersion, &bounds);
  416.     
  417.     DrawDialog(dlg);
  418. #ifndef RUNTIME
  419.     GetDItem(dlg, 1, &kind, &hdl, &bounds);
  420.     SetPort(dlg);
  421.     TextFont(CreditID);
  422.     TextSize(12);
  423.     TextFace(normal);
  424.     ClipRect(&bounds);
  425.     hot         =     bounds;
  426.     hot.left    =    hot.right-2;
  427.     
  428.     kind         = StringWidth("\p • ");
  429.     hdl         = GetResource('STR#', CreditID);
  430.     count        = **(short **) hdl;
  431.     widths     = (short *) NewPtr(2 * count);
  432.     
  433.     for (current = 0; current<count; ++current) {
  434.         GetIndString(string, CreditID, current+1);
  435.         widths[current] = StringWidth(string) + kind;
  436.     }
  437.     
  438.     offset     =     0;
  439.     current     =     0;
  440.     rgn        =    NewRgn();
  441.     lastTicks=    0;
  442.     GetIndString(string, CreditID, current+1);
  443. #endif
  444.  
  445.     while (dlg) {
  446. #ifndef RUNTIME
  447.         while (TickCount() < lastTicks + 2);
  448.         
  449.         lastTicks = TickCount();
  450.         
  451.         SetPort(dlg);
  452.         
  453.         ScrollRect(&bounds, -2, 0, rgn);
  454.         
  455.         ClipRect(&hot);
  456.         MoveTo(bounds.right - offset, bounds.bottom - 3);
  457.         DrawString(string);
  458.         DrawString("\p • ");
  459.         ClipRect(&bounds);
  460.         
  461.         if ((offset += 2) >= widths[current]) {
  462.             current = (current+1) % count;
  463.             offset  = 0;
  464.             GetIndString(string, CreditID, current+1);
  465.         }
  466. #endif
  467.  
  468.         if (WaitNextEvent(mDownMask+keyDownMask+activMask+updateMask+osMask, &ev, 1, nil))
  469.             switch (ev.what) {
  470.             case activateEvt:
  471.                 if ((WindowPtr) ev.message != dlg)
  472.                     DoActivate((WindowPtr)ev.message, (ev.modifiers & activeFlag) != 0);
  473.                     
  474.                 break;
  475.     
  476.             case updateEvt:
  477.                 if ((WindowPtr) ev.message == dlg) {
  478.                     BeginUpdate(dlg);
  479.                     UpdtDialog(dlg, dlg->visRgn);
  480.                     EndUpdate(dlg);
  481.                 } else
  482.                     DoUpdate(DPtrFromWindowPtr((WindowPtr)ev.message));
  483.                 break;
  484.     
  485.             case kOSEvent:
  486.                 switch (ev.message & osEvtMessageMask) { /*high byte of message*/
  487.                 case 0x01000000:
  488.                         gInBackground = ((ev.message & resumeFlag) == 0);
  489.                 }
  490.                 if (!gInBackground)
  491.                     break;
  492.             default:
  493.                 DisposeDialog(dlg);
  494.                 
  495.                 dlg = nil;
  496.                 break;
  497.             }
  498.     }
  499. }
  500.  
  501. static void CenterWindow(DialogPtr dlg)
  502. {
  503.     Rect    *        screen;
  504.     short            hPos;
  505.     short            vPos;
  506.     
  507.     screen    =    &qd.screenBits.bounds;
  508.     hPos    =    screen->right+screen->left-dlg->portRect.right >> 1;
  509.     vPos    =    (screen->bottom-screen->top-dlg->portRect.bottom)/3;
  510.     vPos    +=    screen->top;
  511.     MoveWindow(dlg, hPos, vPos, true);
  512. }    
  513.  
  514. #ifdef RUNTIME
  515.  
  516. typedef long ICON[32];
  517. typedef struct    {
  518.     ICON    icon;
  519.     ICON    mask;
  520. } ICN_;
  521.  
  522. typedef short icm[12];
  523. typedef struct {
  524.     icm    icon;
  525.     icm     mask;
  526. } icm_;
  527.  
  528. static void PlotICN_(ICN_ * icon, Rect * within, IconMode mode)
  529. {
  530.     GrafPtr    port;
  531.     BitMap    bmap;
  532.     BitMap    mask;
  533.     PenState    ps;
  534.     Pattern    ltGray;
  535.     long    *    lg;
  536.     
  537.     GetPort(&port);
  538.     bmap.baseAddr        =    (Ptr) icon;
  539.     bmap.rowBytes        =    4;
  540.     bmap.bounds.top    =    0;
  541.     bmap.bounds.left    =    0;
  542.     bmap.bounds.bottom=    32;
  543.     bmap.bounds.right    =    32;
  544.     
  545.     mask = bmap;
  546.     mask.baseAddr        =    (Ptr) icon->mask;
  547.     
  548.     switch (mode)    {
  549.     case iconGray:
  550.         GetPenState(&ps);
  551.         PenMode(patXor);
  552.         lg     =  (long *)<Gray;
  553.         lg[0] =    0x11004400;
  554.         lg[1] =    lg[0];
  555.         PenPat(<Gray);
  556.         PaintRect(within);
  557.         CopyBits(&mask, &port->portBits, &mask.bounds, within, srcBic, nil);
  558.         PaintRect(within);
  559.         CopyBits(&bmap, &port->portBits, &bmap.bounds, within, srcOr, nil);
  560.         SetPenState(&ps);
  561.         break;
  562.     case iconHilited:
  563.         CopyBits(&mask, &port->portBits, &mask.bounds, within, srcOr, nil);
  564.         CopyBits(&bmap, &port->portBits, &bmap.bounds, within, srcXor, nil);
  565.         break;
  566.     default:
  567.         CopyBits(&mask, &port->portBits, &mask.bounds, within, srcBic, nil);
  568.         CopyBits(&bmap, &port->portBits, &bmap.bounds, within, srcXor, nil);
  569.         break;
  570.     }
  571. }
  572.  
  573. pascal void PlotResICN_(short id, Rect * within, IconMode mode)
  574. {
  575.     char        flags;
  576.     ICN_ **  icon;
  577.     
  578.     if (icon = (ICN_ **) GetResource('ICN#', id))    {
  579.         flags    =    HGetState((Handle) icon);
  580.         HLock((Handle) icon);
  581.         PlotICN_(*icon, within, mode);
  582.         HSetState((Handle) icon, flags);
  583.     }
  584. }
  585.  
  586. static void PlotMiniIcon(icm_ * icon, Rect * within)
  587. {
  588.     GrafPtr    port;
  589.     BitMap    bmap;
  590.     BitMap    mask;
  591.     
  592.     GetPort(&port);
  593.     bmap.baseAddr        =    (Ptr) icon;
  594.     bmap.rowBytes        =    2;
  595.     bmap.bounds.top    =    0;
  596.     bmap.bounds.left    =    0;
  597.     bmap.bounds.bottom=    12;
  598.     bmap.bounds.right    =    16;
  599.     
  600.     mask = bmap;
  601.     mask.baseAddr        =    (Ptr) icon->mask;
  602.     
  603.     CopyBits(&mask, &port->portBits, &mask.bounds, within, srcBic, nil);
  604.     CopyBits(&bmap, &port->portBits, &bmap.bounds, within, srcXor, nil);
  605. }
  606.  
  607. pascal void PlotResMiniIcon(short id, Rect * within)
  608. {
  609.     char        flags;
  610.     icm_ **  icon;
  611.     
  612.     if (icon = (icm_ **) GetResource('icm#', id))    {
  613.         flags    =    HGetState((Handle) icon);
  614.         HLock((Handle) icon);
  615.         PlotMiniIcon(*icon, within);
  616.         HSetState((Handle) icon, flags);
  617.     }
  618. }
  619.  
  620. typedef struct {
  621.       Handle  handle;     /* handle or procedure pointer for this item */
  622.       Rect    bounds;     /* display rectangle for this item */
  623.       char    type;       /* item type - 1 */
  624.       char    data[1];    /* length byte of data */
  625.  } DialogItem;
  626.  
  627. typedef struct {
  628.       short            max_index; /* number of items - 1 */
  629.       DialogItem    items[1]; /* first item in the array */
  630.  } **ItemListHandle;
  631.  
  632. pascal void Append_DITL(DialogPtr dialog, short item_list_ID)
  633. {
  634.     ItemListHandle append_item_list;    /* handle to DITL being appended */
  635.     DialogItem *    item;                /* pointer to item being appended */
  636.     ItemListHandle    dlg_item_list;       /* handle to DLOG's item list */
  637.     short                i;
  638.     short                sz;
  639.     
  640.     dlg_item_list = (ItemListHandle) ((DialogPeek)dialog)->items;
  641.     append_item_list = (ItemListHandle)GetResource('DITL', item_list_ID);
  642.     if (!append_item_list)
  643.       return;
  644.  
  645.    HLock((Handle)append_item_list);
  646.        
  647.     item = (*append_item_list)->items;
  648.     
  649.     for (i=0; i<=(*append_item_list)->max_index; ++i) {
  650.           switch (item->type & 0x7F) {
  651.         case ctrlItem + btnCtrl:
  652.         case ctrlItem + chkCtrl:
  653.         case ctrlItem + radCtrl:
  654.             item->handle = 
  655.                 (Handle)
  656.                     NewControl(
  657.                         (DialogPtr) dialog, &item->bounds,
  658.                         (StringPtr)item->data,
  659.                         true, 0, 0, 1,
  660.                         item->type & 0x03,
  661.                         0);
  662.             break;
  663.  
  664.         case ctrlItem + resCtrl :
  665.             item->handle = (Handle)GetNewControl(*(int*)(item->data + 1), (DialogPtr) dialog);
  666.             (**(ControlHandle)item->handle).contrlRect = item->bounds;
  667.             break;
  668.  
  669.         case statText :
  670.         case editText :
  671.             PtrToHand(item->data + 1, &item->handle, item->data[0]);
  672.             break;
  673.  
  674.         case iconItem :
  675.             item->handle = GetIcon(*(int*)(item->data + 1));
  676.             break;
  677.  
  678.         case picItem :
  679.             item->handle = (Handle)GetPicture(*(int*)(item->data + 1));
  680.             break;
  681.  
  682.         default :
  683.             item->handle = NULL;
  684.           }
  685.  
  686.       sz = (item->data[0] + 1) & 0xFFFE;
  687.       item = (DialogItem *)((char*)item + sz + sizeof(DialogItem));
  688.    }
  689.  
  690.       PtrAndHand(
  691.         (*append_item_list)->items,
  692.       (Handle)dlg_item_list,
  693.       GetHandleSize((Handle) append_item_list) - 2);
  694.    (*dlg_item_list)->max_index += (*append_item_list)->max_index + 1;
  695.    HUnlock((Handle) append_item_list);
  696.    ReleaseResource((Handle) append_item_list);
  697. }
  698.  
  699. pascal void Shorten_DITL(DialogPtr dialog, short shorten)
  700. {
  701.     DialogItem *    item;                /* pointer to item being appended */
  702.     ItemListHandle    dlg_item_list;       /* handle to DLOG's item list */
  703.     short                i;
  704.     short                sz;
  705.     short                restSize = -1;
  706.     
  707.     dlg_item_list = (ItemListHandle) ((DialogPeek)dialog)->items;
  708.  
  709.    HLock((Handle)dlg_item_list);
  710.        
  711.     item         = (*dlg_item_list)->items;
  712.     shorten     = (*dlg_item_list)->max_index - shorten;
  713.     
  714.     for (i=0; i<=(*dlg_item_list)->max_index; ++i) {
  715.         if (i > shorten)
  716.             switch (item->type & 0x7F) {
  717.             case ctrlItem + btnCtrl:
  718.             case ctrlItem + chkCtrl:
  719.             case ctrlItem + radCtrl:
  720.             case ctrlItem + resCtrl :
  721.                 DisposeControl((ControlHandle) item->handle);
  722.                 break;
  723.     
  724.             case statText :
  725.             case editText :
  726.                 DisposeHandle(item->handle);
  727.                 break;
  728.     
  729.             case iconItem :
  730.             case picItem :
  731.                 ReleaseResource(item->handle);
  732.                 break;
  733.     
  734.             default :
  735.                 break;
  736.             }
  737.  
  738.       sz = (item->data[0] + 1) & 0xFFFE;
  739.       item = (DialogItem *)((char*)item + sz + sizeof(DialogItem));
  740.         
  741.         if (i == shorten)
  742.             restSize = (char *) item - (char *) *dlg_item_list;
  743.    }
  744.  
  745.      if (restSize >= 0) {
  746.           SetHandleSize((Handle) dlg_item_list, restSize);
  747.         
  748.        (*dlg_item_list)->max_index = shorten;
  749.     }
  750.     
  751.    HUnlock((Handle) dlg_item_list);
  752. }
  753.  
  754. pascal short Count_DITL(DialogPtr dialog)
  755. {
  756.     return (*(ItemListHandle) ((DialogPeek)dialog)->items)->max_index + 1;
  757. }
  758.  
  759. #endif
  760.  
  761. pascal void Separator(DialogPtr dlg, short item)
  762. {
  763.     short        kind;
  764.     Handle    h;
  765.     Rect        r;
  766.     
  767.     PenPat(&qd.gray);
  768.     GetDItem(dlg, item, &kind, &h, &r);
  769.     FrameRect(&r);
  770.     PenPat(&qd.black);
  771. }
  772.  
  773. static DPtr        Documents[50];
  774. static short    DocCount = 0;
  775.  
  776. pascal void RegisterDocument(DPtr doc)
  777. {
  778.     Documents[DocCount++] = doc;
  779. }
  780.  
  781. pascal void UnregisterDocument(DPtr doc)
  782. {
  783.     short    i,j;
  784.     
  785.     for (i = 0, j = 0; i < DocCount; ++i)
  786.         if (Documents[i] != doc)
  787.             Documents[j++] = Documents[i];
  788.     
  789.     DocCount = j;
  790. }
  791.  
  792. pascal void SetupWindowMenu()
  793. {
  794.     short            i;
  795.     short            item = 0;
  796.     WindowPtr    front;
  797.      WindowPeek    aWindow;
  798.     WindowPeek    nextWindow;
  799.     MenuHandle    menu;
  800.     Str255        name;
  801.     int             needsSeparator = 0;
  802.     
  803.     DisposeMenu(myMenus[windowM]);
  804.     menu = myMenus[windowM]    = GetMenu(windowID);
  805.     
  806.     front = FrontWindow();
  807.     
  808.     for (i = 0; i < DocCount; ++i)
  809.         if (Documents[i]->kind != kDocumentWindow) {
  810.             AppendMenu(menu, "\px");
  811.             GetWTitle(Documents[i]->theWindow, name);
  812.             SetMenuItemText(menu, ++item, name);
  813.             
  814.             if (!((WindowPeek) Documents[i]->theWindow)->visible)
  815.                 SetItemStyle(menu, item, italic);
  816.             else if (Documents[i]->theWindow == front)
  817.                 SetItemMark(menu, item, checkMark);
  818.             
  819.             EnableItem(menu, item);
  820.             needsSeparator = 1;
  821.         }
  822.     
  823.     for (i = 0; i < DocCount; ++i)
  824.         if (Documents[i]->kind == kDocumentWindow) {
  825.             if (needsSeparator && needsSeparator < 2) {
  826.                 AppendMenu(menu, "\p-(");
  827.                 ++item;
  828.             }
  829.             
  830.             AppendMenu(menu, "\px");
  831.             GetWTitle(Documents[i]->theWindow, name);
  832.             SetMenuItemText(menu, ++item, name);
  833.             
  834.             if (!((WindowPeek) Documents[i]->theWindow)->visible)
  835.                 SetItemStyle(menu, item, Documents[i]->dirty ? underline + italic : italic);
  836.             else {
  837.                 if (Documents[i]->dirty)
  838.                     SetItemStyle(menu, item, underline);
  839.                 if (Documents[i]->theWindow == front)
  840.                     SetItemMark(menu, item, checkMark);
  841.             }
  842.             
  843.             EnableItem(menu, item);
  844.             needsSeparator = 2;
  845.         }
  846.     
  847.     for (aWindow = (WindowPeek) FrontWindow(); aWindow; aWindow = nextWindow) {
  848.         nextWindow = aWindow->nextWindow;
  849.         if (aWindow->visible && !Ours((WindowPtr) aWindow)) {
  850.             if (needsSeparator && needsSeparator < 3) {
  851.                 AppendMenu(menu, "\p-(");
  852.                 ++item;
  853.             }
  854.             
  855.             AppendMenu(menu, "\px");
  856.             GetWTitle((WindowPtr) aWindow, name);
  857.             SetMenuItemText(menu, ++item, name);
  858.             
  859.             if ((WindowPtr) aWindow == front)
  860.                 SetItemMark(menu, item, checkMark);
  861.             
  862.             EnableItem(menu, item);
  863.             needsSeparator = 3;
  864.         }
  865.     }
  866. }
  867.  
  868. static void AnointWindow(WindowPtr win)
  869. {
  870.     if (!((WindowPeek) win)->visible)
  871.         ShowWindow(win);
  872.     SelectWindow(win);
  873. }
  874.  
  875. pascal void DoSelectWindow(short item)
  876. {
  877.     short            i;
  878.      WindowPeek    aWindow;
  879.     WindowPeek    nextWindow;
  880.     MenuHandle    menu;
  881.     int             needsSeparator = 0;
  882.     
  883.     menu = myMenus[windowM];
  884.     
  885.     for (i = 0; i < DocCount; ++i)
  886.         if (Documents[i]->kind != kDocumentWindow) {
  887.             if (!--item) {
  888.                 AnointWindow(Documents[i]->theWindow);
  889.                 
  890.                 return;
  891.             }
  892.             needsSeparator = 1;
  893.         }
  894.     
  895.     for (i = 0; i < DocCount; ++i)
  896.         if (Documents[i]->kind == kDocumentWindow) {
  897.             if (needsSeparator && needsSeparator < 2) {
  898.                 --item;
  899.             }
  900.             
  901.             if (!--item) {
  902.                 AnointWindow(Documents[i]->theWindow);
  903.                 
  904.                 return;
  905.             }
  906.             
  907.             needsSeparator = 2;
  908.         }
  909.     
  910.     for (aWindow = (WindowPeek) FrontWindow(); aWindow; aWindow = nextWindow) {
  911.         nextWindow = aWindow->nextWindow;
  912.         if (aWindow->visible && !Ours((WindowPtr) aWindow)) {
  913.             if (needsSeparator && needsSeparator < 3) {
  914.                 --item;
  915.             }
  916.             
  917.             if (!--item) {
  918.                 AnointWindow((WindowPtr) aWindow);
  919.                 
  920.                 return;
  921.             }
  922.             
  923.             needsSeparator = 3;
  924.         }
  925.     }
  926. }
  927.  
  928. /* Borrowed from tech note 263 */
  929.  
  930. #define kKosherModifiers    0x0E00        // We keep only option & shift
  931. #define kMaskVirtualKey     0x0000FF00     // get virtual key from event message
  932.                                            // for KeyTrans
  933. #define kUpKeyMask          0x0080
  934. #define kShiftWord          8              // we shift the virtual key to mask it
  935.                                            // into the keyCode for KeyTrans
  936. #define kMaskASCII1         0x00FF0000     // get the key out of the ASCII1 byte
  937. #define kMaskASCII2         0x000000FF     // get the key out of the ASCII2 byte
  938.  
  939. pascal Boolean WeirdChar(const EventRecord * ev, short modifiers, char ch)
  940. {
  941.       short    keyCode;
  942.       long     virtualKey, keyInfo, lowChar, highChar, state, keyCId;
  943.       Handle   hKCHR;
  944.     Ptr         KCHRPtr;
  945.  
  946.     if ((ev->what == keyDown) || (ev->what == autoKey)) {
  947.  
  948.         // see if the command key is down.  If it is, find out the ASCII
  949.         // equivalent for the accompanying key.
  950.  
  951.         if ((ev->modifiers & 0xFF00) == modifiers) {
  952.  
  953.             virtualKey     = (ev->message & kMaskVirtualKey) >> kShiftWord;
  954.             keyCode          = (ev->modifiers & kKosherModifiers & ~modifiers) | virtualKey;
  955.             state           = 0;
  956.  
  957.             hKCHR            = nil;  /* set this to nil before starting */
  958.              KCHRPtr         = (Ptr)GetEnvirons(smKCHRCache);
  959.  
  960.             if ( !KCHRPtr ) {
  961.                 keyCId     =    GetScript((short) GetEnvirons(smKeyScript), smScriptKeys);
  962.                 hKCHR        =    GetResource('KCHR', (short) keyCId);
  963.                 KCHRPtr    = *hKCHR;
  964.             }
  965.  
  966.             if (KCHRPtr) {
  967.                 keyInfo = KeyTrans(KCHRPtr, keyCode, &state);
  968.                 if (hKCHR)
  969.                     ReleaseResource(hKCHR);
  970.             } else
  971.                 keyInfo = ev->message;
  972.  
  973.             lowChar =  keyInfo &  kMaskASCII2;
  974.             highChar = (keyInfo & kMaskASCII1) >> 16;
  975.             if (lowChar == ch || highChar == ch)
  976.                 return true;
  977.  
  978.         }  // end the command key is down
  979.     }  // end key down event
  980.  
  981.     return false;
  982. }
  983.